<?php
/**
 * @link https://ym2.cleverstone.top
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace builder\base;

use Yii;
use yii\web\User;
use yii\db\Connection;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use builder\helper\Tab;
use builder\helper\Tree;
use builder\helper\Table;
use builder\helper\Form;
use builder\helper\Lists;
use builder\helper\TreeTable;
use builder\helper\FormStep;
use builder\helper\Menu;
use builder\behaviors\RbacBehavior;
use builder\helper\App;
use builder\table\util\ToolbarTab;
use builder\tree_table\util\TTToolbarTab;

/**
 * 控制器继承类
 * @property-read User $user Web User
 * @property-read Connection $db DB连接实例
 * @property-read \yii\web\Session $session session会话实例
 * @property-read \yii\caching\CacheInterface $cache cache缓存实例
 * @property-read \builder\ViewBuilder $viewBuilder 视图构建器
 * @property-read \builder\uploads\Upload $uploadManager 文件管理器
 * ============================ 表格助手 ============================
 * @property-read \builder\table\util\TableHeadHelper $tableHead 表格行操作助手
 * @property-read \builder\table\util\RowOperationHelper $rowOperation 表格行操作助手
 * @property-read \builder\table\util\ToolbarCustomHelper $toolbarCustom 表格自定义工具项助手
 * @property-read \builder\table\util\ToolbarFilterHelper $toolbarFilter 表格工具筛选项助手
 * @property-read \builder\table\util\ToolbarTab $toolbarTab 表格工具选项卡助手
 * ============================ 表单助手 ============================
 * @property-read \builder\form\util\ControlHelper $formControl 表单控件助手
 * @property-read \builder\form\util\SredirectHelper $submittedRedirect 表单回调窗口助手
 * @property-read \builder\form\util\control\dselect\DselectHelper $selectDynamic 表单动态下拉控件助手
 * @property-read \builder\form\util\control\dctrl\DctrlHelper $dynamicControl 表单动态控件(项)助手
 * ============================ 分步表单助手 ============================
 * @property-read \builder\form_step\util\FssrHelper $fssRedirect 分步表单回调窗口助手
 * @property-read \builder\form_step\util\StepItemHelper $stepItem 分步表单设置分类项助手
 * ============================ 列表助手 ============================
 * @property-read \builder\lists\util\ListRowsHelper $listRows 列表行数据助手
 * ============================ 选项卡助手 ============================
 * @property-read \builder\tab\util\TabItemHelper $tabItem 选项卡项助手
 * ============================ 树组件助手 ============================
 * @property-read \builder\tree\util\OperationItemHelper $operationItem 树组件操作项助手
 * ============================ 树表格助手 ============================
 * @property-read \builder\tree_table\util\TTRowOperationHelper $ttRowOperation 树表格行操作助手
 * @property-read \builder\tree_table\util\TTTableHeadHelper $treeTableHead 树表格行操作助手
 * @property-read \builder\tree_table\util\TTToolbarCustomHelper $ttToolbarCustom 树表格自定义工具项助手
 * @property-read \builder\tree_table\util\TTToolbarFilterHelper $ttToolbarFilter 树表格工具筛选项助手
 * @property-read \builder\tree_table\util\TTToolbarTab $ttToolbarTab 表格工具选项卡助手
 * ============================ 菜单助手 ============================
 * @property-read \builder\menu\util\RowEventsHelper $rowEvents 菜单行事件助手
 * @property-read \builder\menu\util\MenuToolbarHelper $menuToolbar 菜单工具助手
 * @author cleverstone
 * @since ym2.0
 */
class BaseController extends Controller
{
    use Http;

    /**
     * @var string 视图继承路径.
     */
    public $layout = '@builder/layouts/main.php';

    /**
     * HTTP METHOD
     * @var array Verbs to specify the actions.
     */
    public $actionVerbs = [];

    /**
     * 只有游客可以访问
     * @var array Define actions that don't require authorization.
     */
    public $guestActions = [];

    /**
     * 只有游客和登录用户可以访问
     * @var array The guest and authenticated users can access current action.
     */
    public $publicActions = [];

    /**** 属性: 如果action id不存在属性 $guestActions 或 $publicActions 中， 则该action id只有认证用户可以访问, 且需要RBAC授权. ****/


    /**
     * 只有登录用户可以访问, 但不需要RBAC访问控制
     * @var array Register undetected action ids for RBAC.
     */
    public $undetectedActions = [];

    /**
     * Returns a list of behaviors that this component should behave as.
     *
     * Child classes may override this method to specify the behaviors they want to behave as.
     *
     * The return value of this method should be an array of behavior objects or configurations
     * indexed by behavior names. A behavior configuration can be either a string specifying
     * the behavior class or an array of the following structure:
     *
     * ```php
     * 'behaviorName' => [
     *     'class' => 'BehaviorClass',
     *     'property1' => 'value1',
     *     'property2' => 'value2',
     * ]
     * ```
     *
     * Note that a behavior class must extend from [[Behavior]]. Behaviors can be attached using a name or anonymously.
     * When a name is used as the array key, using this name, the behavior can later be retrieved using [[getBehavior()]]
     * or be detached using [[detachBehavior()]]. Anonymous behaviors can not be retrieved or detached.
     *
     * Behaviors declared in this method will be attached to the component automatically (on demand).
     *
     * @return array the behavior configurations.
     */
    public function behaviors()
    {
        $parentBehaviors = parent::behaviors();

        $actionVerbsFilter = $this->verbsFilter();
        $accessCtrlFilter = $this->accessControlFilter();
        $rgacFilter = $this->rbacFilter();

        return array_merge(
            $parentBehaviors,
            $actionVerbsFilter,
            $accessCtrlFilter,
            $rgacFilter
        );
    }

    /**
     * This is action verbs filters.
     * @return array
     */
    public function verbsFilter()
    {
        if (!empty($this->actionVerbs)) {
            return [
                'verbs' => [
                    'class' => VerbFilter::class,
                    'actions' => $this->actionVerbs,
                ],
            ];
        } else {
            return [];
        }
    }

    /**
     * This is access control filters.
     * @return array
     */
    public function accessControlFilter()
    {
        if (
            !in_array($this->action->id, $this->guestActions, true)
            && !in_array($this->action->id, $this->publicActions, true)
        ) {
            // 只有认证用户可以访问
            return [
                'access' => [
                    'class' => AccessControl::class,
                    'only' => [$this->action->id],
                    'rules' => [
                        [
                            'allow' => true,
                            'roles' => ['@'],
                        ],
                    ],
                ],
            ];
        } elseif (in_array($this->action->id, $this->guestActions, true)) {
            // 只有游客可以访问
            return [
                'access' => [
                    'class' => AccessControl::class,
                    'only' => [$this->action->id],
                    'rules' => [
                        [
                            'allow' => true,
                            'roles' => ['?'],
                        ],
                    ],
                ],
            ];
        } else {
            // 游客和认证用户都可以访问
            return [];
        }
    }

    /**
     * Rbac controls filters.
     * @return array
     */
    public function rbacFilter()
    {
        if (
            !in_array($this->action->id, $this->guestActions, true)
            && !in_array($this->action->id, $this->publicActions, true)
            && !in_array($this->action->id, $this->undetectedActions, true)
        ) {
            return [
                'rbac' => [
                    'class' => RbacBehavior::class,
                ],
            ];
        } else {
            return [];
        }
    }

    /**
     * 设置局部继承主题
     * @return bool
     */
    public function setLayoutPartial()
    {
        $this->layout = '@builder/layouts/partial.php';
        return true;
    }

    /**
     * 设置主布局继承主题
     * @return bool
     */
    public function setLayoutMain()
    {
        $this->layout = '@builder/layouts/main.php';
        return true;
    }

    /**
     * 内容渲染扩展
     * @param string $content
     * @param bool $partialLayout
     * @return string
     */
    public function renderContentX($content, $partialLayout = true)
    {
        if ($partialLayout) {
            $this->setLayoutPartial();
        }

        return parent::renderContent($content);
    }

    /**
     * 去登录
     * @return \yii\web\Response
     */
    public function goLogin()
    {
        return $this->response->redirect([App::params('admin.route.login')]);
    }

    /**
     * 获取DB实例
     * @return \yii\db\Connection
     */
    public function getDb()
    {
        return Yii::$app->db;
    }

    /**
     * 获取session实例
     * @return \yii\web\Session
     */
    public function getSession()
    {
        return Yii::$app->session;
    }

    /**
     * 获取cache实例
     * @return \yii\caching\CacheInterface
     */
    public function getCache()
    {
        return Yii::$app->cache;
    }

    /**
     * 获取Web User
     * @return User
     */
    public function getUser()
    {
        return Yii::$app->getUser();
    }

    /**
     * 获取视图构建器
     * @return \builder\ViewBuilder
     */
    public function getViewBuilder()
    {
        return Yii::$app->viewBuilder;
    }

    /**
     * 获取文件管理器
     * @return \builder\uploads\Upload
     */
    public function getUploadManager()
    {
        return Yii::$app->uploadManager;
    }

    /**
     * 表格表头助手
     * @return \builder\table\util\TableHeadHelper
     * @throws InvalidInstanceException
     */
    public function getTableHead()
    {
        return Table::tableHead();
    }

    /**
     * 表格行操作项助手
     * @return \builder\table\util\RowOperationHelper
     * @throws InvalidInstanceException
     */
    public function getRowOperation()
    {
        return Table::rowOperation();
    }

    /**
     * 表格自定义工具项助手
     * @return \builder\table\util\ToolbarCustomHelper
     * @throws InvalidInstanceException
     */
    public function getToolbarCustom()
    {
        return Table::toolbarCustom();
    }

    /**
     * 表格工具筛选项助手
     * @return \builder\table\util\ToolbarFilterHelper
     * @throws InvalidInstanceException
     */
    public function getToolbarFilter()
    {
        return Table::toolbarFilter();
    }

    /**
     * 表格工具选项卡助手
     * @return ToolbarTab
     */
    public function getToolbarTab()
    {
        return new ToolbarTab();
    }

    /**
     * 表单控件助手
     * @return \builder\form\util\ControlHelper
     * @throws InvalidInstanceException
     */
    public function getFormControl()
    {
        return Form::formControl();
    }

    /**
     * 表单回调窗口助手
     * @return \builder\form\HelperInterface
     * @throws InvalidInstanceException
     */
    public function getSubmittedRedirect()
    {
        return Form::submittedRedirect();
    }

    /**
     * 表单动态下拉控件助手
     * @return \builder\form\HelperInterface
     * @throws InvalidInstanceException
     */
    public function getSelectDynamic()
    {
        return Form::selectDynamic();
    }

    /**
     * 表单动态控件(项)助手
     * @return \builder\form\HelperInterface
     * @throws InvalidInstanceException
     */
    public function getDynamicControl()
    {
        return Form::dynamicControl();
    }

    /**
     * 分步表单回调窗口助手
     * @return \builder\form_step\HelperInterface
     * @throws InvalidInstanceException
     */
    public function getFssRedirect()
    {
        return FormStep::fssRedirect();
    }

    /**
     * 分步表单设置分类项助手
     * @return \builder\form_step\HelperInterface
     * @throws InvalidInstanceException
     */
    public function getStepItem()
    {
        return FormStep::stepItem();
    }

    /**
     * 列表行数据助手
     * @return \builder\lists\util\ListRowsHelper
     * @throws InvalidInstanceException
     */
    public function getListRows()
    {
        return Lists::listRows();
    }

    /**
     * 选项卡项助手
     * @return \builder\tab\util\TabItemHelper
     * @throws InvalidInstanceException
     */
    public function getTabItem()
    {
        return Tab::tabItem();
    }

    /**
     * 树组件操作项助手
     * @return \builder\tree\util\OperationItemHelper
     * @throws InvalidInstanceException
     */
    public function getOperationItem()
    {
        return Tree::operationItem();
    }

    /**
     * 树表格表头助手
     * @return \builder\tree_table\util\TTTableHeadHelper
     * @throws InvalidInstanceException
     */
    public function getTreeTableHead()
    {
        return TreeTable::treeTableHead();
    }

    /**
     * 树表格行操作项助手
     * @return \builder\tree_table\util\TTRowOperationHelper
     * @throws InvalidInstanceException
     */
    public function getTtRowOperation()
    {
        return TreeTable::ttRowOperation();
    }

    /**
     * 树表格自定义工具项助手
     * @return \builder\tree_table\util\TTToolbarCustomHelper
     * @throws InvalidInstanceException
     */
    public function getTtToolbarCustom()
    {
        return TreeTable::ttToolbarCustom();
    }

    /**
     * 树表格工具筛选项助手
     * @return \builder\tree_table\util\TTToolbarFilterHelper
     * @throws InvalidInstanceException
     */
    public function getTtToolbarFilter()
    {
        return TreeTable::ttToolbarFilter();
    }

    /**
     * @return TTToolbarTab
     */
    public function getTtToolbarTab()
    {
        return new TTToolbarTab();
    }

    /**
     * 菜单行事件助手
     * @return \builder\menu\util\RowEventsHelper
     * @throws InvalidInstanceException
     */
    public function getRowEvents()
    {
        return Menu::rowEvents();
    }

    /**
     * 菜单工具栏助手
     * @return \builder\menu\util\MenuToolbarHelper
     * @throws InvalidInstanceException
     */
    public function getMenuToolbar()
    {
        return Menu::menuToolbar();
    }
}